#include "VSScene.h"
#include "VSResourceManager.h"
#include "VSGraphicInclude.h"
#include "VSUpdateThread.h"
#include "VSStream.h"
using namespace VSEngine2;
IMPLEMENT_RTTI(VSScene,VSObject)
BEGIN_ADD_PROPERTY(VSScene,VSObject)
REGISTER_PROPERTY(m_pLight,Light,VSProperty::F_SAVE_LOAD_CLONE)
REGISTER_PROPERTY(m_pCamera,Camera,VSProperty::F_SAVE_LOAD_CLONE)
REGISTER_PROPERTY(m_pDynamic,Dynamic,VSProperty::F_SAVE_LOAD_CLONE)
REGISTER_PROPERTY(m_pStaticRoot,StaticRoot,VSProperty::F_SAVE_LOAD_CLONE)
END_ADD_PROPERTY
IMPLEMENT_INITIAL_BEGIN(VSScene)
IMPLEMENT_INITIAL_END

VSScene::VSScene()
{
	m_pLight.Clear();
	m_pCamera.Clear();

	m_pAllLight.Clear();
	m_pAllCamera.Clear();
	m_pStaticRoot = NULL;
}
VSScene::~VSScene()
{
	m_pLight.Clear();
	m_pCamera.Clear();

	m_pAllLight.Clear();
	m_pAllCamera.Clear();

	m_pDynamic.Clear();
	m_pStaticRoot = NULL;
}
void VSScene::Update(double dAppTime)
{
	struct UpdateAVObject
	{
		VSAVObject * pAVObject;
		double dAppTime;
	};
	for(unsigned int i = 0 ; i < m_pCamera.GetNum() ; i++)
	{

		UpdateAVObject CameraUpdate;
		CameraUpdate.pAVObject = m_pCamera[i];
		CameraUpdate.dAppTime = dAppTime;
		ENQUEUE_UNIQUE_UPDATE_COMMAND_ONEPARAMETER(VSUpdateCamera,
			UpdateAVObject,CameraUpdate,CameraUpdate,
		{
			CameraUpdate.pAVObject->UpdateAll(CameraUpdate.dAppTime); 
		})
			CameraUpdate.pAVObject->UpdateAll(CameraUpdate.dAppTime); 
		ENQUEUE_UNIQUE_RENDER_COMMAND_END
	}


	for(unsigned int i = 0 ; i < m_pLight.GetNum() ; i++)
	{
		UpdateAVObject LightUpdate;
		LightUpdate.pAVObject = m_pLight[i];
		LightUpdate.dAppTime = dAppTime;
		ENQUEUE_UNIQUE_UPDATE_COMMAND_ONEPARAMETER(VSUpdateLight,
			UpdateAVObject,LightUpdate,LightUpdate,
		{
			LightUpdate.pAVObject->UpdateAll(LightUpdate.dAppTime); 
		})
			LightUpdate.pAVObject->UpdateAll(LightUpdate.dAppTime); 
		ENQUEUE_UNIQUE_RENDER_COMMAND_END
	}
	
	
	struct UpdateNode
	{
		VSSpatial * pSpatial;
		double dAppTime;
	};
	if (m_pStaticRoot)
	{
		UpdateNode StaticUpdateNode;
		StaticUpdateNode.pSpatial = m_pStaticRoot;
		StaticUpdateNode.dAppTime = dAppTime;
		ENQUEUE_UNIQUE_UPDATE_COMMAND_ONEPARAMETER(VSUpdateStaticNode,
			UpdateNode,StaticUpdateNode,StaticUpdateNode,
		{
			StaticUpdateNode.pSpatial->UpdateAll(StaticUpdateNode.dAppTime); 
		})
			StaticUpdateNode.pSpatial->UpdateAll(StaticUpdateNode.dAppTime); 
		ENQUEUE_UNIQUE_RENDER_COMMAND_END
	}

	for (unsigned int i = 0; i < m_pDynamic.GetNum(); i++)	
	{ 
		UpdateNode DynamicUpdateNode;
		DynamicUpdateNode.pSpatial = m_pDynamic[i];
		DynamicUpdateNode.dAppTime = dAppTime;
		ENQUEUE_UNIQUE_UPDATE_COMMAND_ONEPARAMETER(VSUpdateDynamicNode,
			UpdateNode,DynamicUpdateNode,DynamicUpdateNode,
		{
			DynamicUpdateNode.pSpatial->UpdateAll(DynamicUpdateNode.dAppTime); 
		})
			DynamicUpdateNode.pSpatial->UpdateAll(DynamicUpdateNode.dAppTime); 
		ENQUEUE_UNIQUE_RENDER_COMMAND_END
	} 

}
void VSScene::CollectUpdateInfo()
{
	if(m_pAllCamera.GetNum() > 0)
		m_pAllCamera.Clear();
	if(m_pAllLight.GetNum() > 0)
		m_pAllLight.Clear();
	if(m_pCamera.GetNum() > 0)
		m_pAllCamera.AddElement(m_pCamera,0,m_pCamera.GetNum() - 1);



	if(m_pStaticRoot)
	{
		if(m_pStaticRoot->m_pAllCamera.GetNum() > 0)
			m_pAllCamera.AddElement(m_pStaticRoot->m_pAllCamera,0,m_pStaticRoot->m_pAllCamera.GetNum() - 1);
	}


	for(unsigned int i = 0 ; i < m_pDynamic.GetNum() ; i++)
	{
		if(m_pDynamic[i])
		{
			if(m_pDynamic[i]->m_pAllCamera.GetNum() > 0)
				m_pAllCamera.AddElement(m_pDynamic[i]->m_pAllCamera,0,m_pDynamic[i]->m_pAllCamera.GetNum() - 1);
		}

	}

	if(m_pLight.GetNum() > 0)
		m_pAllLight.AddElement(m_pLight,0,m_pLight.GetNum() - 1);


	if(m_pStaticRoot)
	{
		if(m_pStaticRoot->m_pAllLight.GetNum() > 0)
			m_pAllLight.AddElement(m_pStaticRoot->m_pAllLight,0,m_pStaticRoot->m_pAllLight.GetNum() - 1);
	}



	for(unsigned int i = 0 ; i < m_pDynamic.GetNum() ; i++)
	{
		if(m_pDynamic[i])
		{
			if(m_pDynamic[i]->m_pAllLight.GetNum() > 0)
				m_pAllLight.AddElement(m_pDynamic[i]->m_pAllLight,0,m_pDynamic[i]->m_pAllLight.GetNum() - 1);
		}


	}
}
void VSScene::AddObject(VSSpatial * pObject)
{
	if (pObject)
	{
		m_pDynamic.AddElement(pObject);
	}

}
void VSScene::DeleteObject(VSSpatial *pObject)
{
	
	if (!pObject)
	{

		for (unsigned int i = 0 ; i < m_pDynamic.GetNum() ; i++)
		{
			if (pObject == m_pDynamic[i])
			{
				m_pDynamic.Erase(i);
				return ;
			}
		}
		VSNode * pSpatial = DynamicCast<VSNode>(pObject->GetParent());
		if (pSpatial)
		{
			pSpatial->DeleteChild(pObject);
		}
	}
}

void VSScene::DeleteAllObject()
{
	m_pDynamic.Clear();
	m_pStaticRoot = NULL;
}

void VSScene::ComputeVisibleSet(VSCuller & Culler,bool bNoCull,double dAppTime)
{
	if(m_pStaticRoot)
	{

		m_pStaticRoot->ComputeVisibleSet(Culler,bNoCull,dAppTime);

	}
	for(unsigned int i = 0 ; i < m_pDynamic.GetNum() ; i++)
	{
		if(m_pDynamic[i])
		{

			m_pDynamic[i]->ComputeVisibleSet(Culler,bNoCull,dAppTime);
		}

	}
}
//add loaded Scene
bool VSScene::Build()
{

		
	
	VSArray<VSSpatial *> pStatic;
	for (unsigned int i = 0 ; i < m_pDynamic.GetNum() ; i++)
	{
		m_pDynamic[i]->UpdateAll(0);
		if(!m_pDynamic[i]->IsDynamic())
		{
			pStatic.AddElement(m_pDynamic[i]);
		}
		
	}
	m_pStaticRoot = VS_NEW VSQuadNode();
	if(!m_pStaticRoot->RecursiveBuild(pStatic))
		return 0;



	return 1;
}
bool VSQuadNode::RecursiveBuild(const VSArray<VSSpatial *> &pObjectArray)
{
	if (!pObjectArray.GetNum())
	{
		return 0;
	}
	if (pObjectArray.GetNum() < MAX_NUM)
	{
		for (unsigned int i = 0 ; i < pObjectArray.GetNum() ; i++)
		{
			AddChild(pObjectArray[i]);
		}
		return 1;
	}
	bool bFound = false;
	VSAABB3 Total;
	for (unsigned int i = 0 ; i < pObjectArray.GetNum() ; i++)
	{
		if (pObjectArray[i])
		{
			const VSAABB3 & WorldAABB = pObjectArray[i]->GetWorldAABB();

			if (!bFound)
			{
				Total = WorldAABB;
				bFound = true;
			}
			else
			{
				Total = Total.MergAABB(WorldAABB);
			}

		}
	}

	VSAABB3 ChildAABB[4];
	Total.GetQuadAABB(ChildAABB);
	VSArray<VSSpatial *> ChildStatic[4];
	for (unsigned int i = 0 ; i < pObjectArray.GetNum() ; i++)
	{
		if (!pObjectArray[i])
		{
			continue;
		}
		for (unsigned int j = 0 ; j < 4 ; j++)
		{
			if (ChildAABB[j].RelationWith(pObjectArray[i]->GetWorldTranslate()) != VSOUT)
			{
				ChildStatic[j].AddElement(pObjectArray[i]);
				break;
			}
		}
	}
	for (unsigned int i = 0 ; i < 4 ; i++)
	{
		if (ChildStatic[i].GetNum())
		{
			VSQuadNode * pQuadNode = VS_NEW VSQuadNode();
			AddChild(pQuadNode);
			if(!pQuadNode->RecursiveBuild(ChildStatic[i]))
				return 0;
		}
	}
	return 1;
}